﻿using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace PotatoSoft.Middleware
{
    using ImageProcessing;

    public enum Depths { DEPTH_8U, DEPTH_8S, DEPTH_16U, DEPTH_16S, DEPTH_32S, DEPTH_32F, DEPTH_64F }
    public enum Modif { CREATE, ADD_NUM, ADD_IMG, SUB_NUM, SUB_IMG, MUL_NUM, MUL_IMG, DIV_NUM, DIV_IMG }

    struct HistEntry
    {
        private Modif idFunc;
        private DateTime timeOfModif;
        private String argOfFunc;

        public HistEntry(Modif _idFunc, DateTime _timeOfModif, String _argOfFunc)
        {
            idFunc = _idFunc;
            timeOfModif = _timeOfModif;
            argOfFunc = _argOfFunc;
        }
        public Modif IdFunc
        {
            get
            {
                return idFunc;
            }
        }
        public DateTime TimeOfModif
        {
            get
            {
                return timeOfModif;
            }
        }
        public String ArgOfFunc
        {
            get
            {
                return argOfFunc;
            }
        }
    }
    //klasa historii
    public class ImagePotato
    {
        //historia
        ArrayList histOfModif;

        protected int nChannels;
        protected Depths depth;
        protected int width;
        protected int height;
        protected int wdStep;

        protected DateTime creationTime;
        protected String name = "";

        public int Width
        {
            get
            {
                return width;
            }
        }
        public int Height
        {
            get
            {
                return height;
            }
        }
        public int WdStep
        {
            get
            {
                return wdStep;
            }
        }
        public ArrayList HistOfModif
        {
            get
            {
                return histOfModif;
            }
        }
        public DateTime CreationTime
        {
            get
            {
                return creationTime;
            }
        }
        public String Name
        {
            get
            {
                return Name;
            }

            set
            {
                Name = value;
            }
        }

        public ImagePotato(int _nChannels, Depths _depth)
        {
            nChannels = _nChannels;
            depth = _depth;
            creationTime = DateTime.Now;
            histOfModif = new ArrayList();
            histOfModif.Add(new HistEntry(Modif.CREATE, DateTime.Now, ""));
        }
    }

    public class ImagePotato_8u : ImagePotato
    {
        //buffor
        private byte[] data;
        //histogram
        private byte[] histogram;

        //obrazek dla wpf
        Image imageSrc;

        public ImagePotato_8u()
            : base(1, Depths.DEPTH_8U)
        {
            width = 1;
            height = 1;
            wdStep = width;
            data = new byte[1];
            data[0] = 0;
        }

        public ImagePotato_8u(int _width, int _height, byte[] _data)
            : base(1, Depths.DEPTH_8U)
        {
            width = _width;
            height = _height;
            wdStep = _width;
            data = _data;
        }

        //konstruktor z pliku
        public ImagePotato_8u(String _name)
            : base(1, Depths.DEPTH_8U)
        {
            name = _name;
            ImageProcessing.cvLoad_8u(_name, ref data, ref width, ref height, ref wdStep);
        }

        //konstruktor kopiujący
        public ImagePotato_8u(ImagePotato_8u img)
            : base(1, Depths.DEPTH_8U)
        {
            width = img.Width;
            height = img.Height;
            wdStep = img.WdStep;
            int size = width * height;
            data = new byte[size];
            for (int i = 0; i < size; i++)
            {
                data[i] = img[i];
            }
        }

        //operator []
        public byte this[int i]
        {
            get
            {
                return data[i];
            }

            set
            {
                data[i] = value;
            }
        }

        //operator + byte
        public static ImagePotato_8u operator +(ImagePotato_8u img, byte num)
        {
            ImagePotato_8u imgPl = new ImagePotato_8u(img);
            for (int i = 0; i < imgPl.Width * imgPl.Height; i++)
                imgPl[i] += num;
            return imgPl;
        }
        //operator + ImagePotato_8u
        public static ImagePotato_8u operator +(ImagePotato_8u img1, ImagePotato_8u img2)
        {
            int hgh;
            int wdh;
            ImagePotato_8u imgSum = new ImagePotato_8u(img1);

            if (img1.Height <= img2.Height)
                hgh = img1.Height;
            else
                hgh = img2.Height;

            if (img1.Width <= img2.Width)
                wdh = img1.Width;
            else
                wdh = img2.Width;

            for (int i = 0; i < hgh; i++)
                for (int j = 0; j < wdh; j++)
                {
                    imgSum[j + i * imgSum.wdStep] += img2[j + i * img2.wdStep];
                }
            return imgSum;
        }

        //operator * byte
        public static ImagePotato_8u operator *(ImagePotato_8u img, byte num)
        {
            ImagePotato_8u imgPl = new ImagePotato_8u(img);
            for (int i = 0; i < imgPl.Width * imgPl.Height; i++)
                imgPl[i] *= num;
            return imgPl;
        }
        //operator * ImagePotato_8u
        public static ImagePotato_8u operator *(ImagePotato_8u img1, ImagePotato_8u img2)
        {
            int hgh;
            int wdh;
            ImagePotato_8u imgSum = new ImagePotato_8u(img1);

            if (img1.Height <= img2.Height)
                hgh = img1.Height;
            else
                hgh = img2.Height;

            if (img1.Width <= img2.Width)
                wdh = img1.Width;
            else
                wdh = img2.Width;

            for (int i = 0; i < hgh; i++)
                for (int j = 0; j < wdh; j++)
                {
                    imgSum[j + i * imgSum.wdStep] *= img2[j + i * img2.wdStep];
                }
            return imgSum;
        }

        //operator - byte
        public static ImagePotato_8u operator -(ImagePotato_8u img, byte num)
        {
            ImagePotato_8u imgPl = new ImagePotato_8u(img);
            for (int i = 0; i < imgPl.Width * imgPl.Height; i++)
                imgPl[i] -= num;
            return imgPl;
        }
        //operator - ImagePotato_8u
        public static ImagePotato_8u operator -(ImagePotato_8u img1, ImagePotato_8u img2)
        {
            int hgh;
            int wdh;
            ImagePotato_8u imgSum = new ImagePotato_8u(img1);

            if (img1.Height <= img2.Height)
                hgh = img1.Height;
            else
                hgh = img2.Height;

            if (img1.Width <= img2.Width)
                wdh = img1.Width;
            else
                wdh = img2.Width;

            for (int i = 0; i < hgh; i++)
                for (int j = 0; j < wdh; j++)
                {
                    imgSum[j + i * imgSum.wdStep] -= img2[j + i * img2.wdStep];
                }
            return imgSum;
        }

        //operator / byte
        public static ImagePotato_8u operator /(ImagePotato_8u img, byte num)
        {
            ImagePotato_8u imgPl = new ImagePotato_8u(img);
            for (int i = 0; i < imgPl.Width * imgPl.Height; i++)
                imgPl[i] /= num;
            return imgPl;
        }
        //operator / ImagePotato_8u
        public static ImagePotato_8u operator /(ImagePotato_8u img1, ImagePotato_8u img2)
        {
            int hgh;
            int wdh;
            ImagePotato_8u imgSum = new ImagePotato_8u(img1);

            if (img1.Height <= img2.Height)
                hgh = img1.Height;
            else
                hgh = img2.Height;

            if (img1.Width <= img2.Width)
                wdh = img1.Width;
            else
                wdh = img2.Width;

            for (int i = 0; i < hgh; i++)
                for (int j = 0; j < wdh; j++)
                {
                    imgSum[j + i * imgSum.wdStep] /= img2[j + i * img2.wdStep];
                }
            return imgSum;
        }

        public byte[] Buffer
        {
            get
            {
                return data;
            }
        }
        public float Mean
        {
            get
            {
                return ImageProcessing.cvMean_8u(data, width, height, wdStep);
            }
        }
        public float StdDev
        {
            get
            {
                return ImageProcessing.cvStdDev_8u(data, width, height, wdStep);
            }
        }
        public byte[] Histogram
        {
            get
            {
                if (histogram == null)
                    histogram = new byte[256];
                ImageProcessing.cvHist_8u(data, ref histogram, 0, 256, 256, width, height, wdStep, null);
                return histogram;
            }
        }
        //własność zwraca źródło obrazka dla wpf
        public WriteableBitmap ImageSrc
        {
            get
            {
                if (imageSrc == null)
                    imageSrc = new Image();

                WriteableBitmap bitmap = new WriteableBitmap(width, height, 96, 96, System.Windows.Media.PixelFormats.Gray8, null);
                bitmap.WritePixels(new Int32Rect(0, 0, width, height), data, wdStep, 0);
                return bitmap;
            }
        }
    }
}
